'use strict';
const deezerApi = require('deezer-request2');
const getAlbumTracks = require('./getAlbumTracks');
const urlRegex = require('url-regex');
const axios = require('axios');
const signale = require('signale');
const spotifyURI = require('spotify-uri');
const spotify2Deezer = require('./spotify');
const Tidal = require('tidal-api-wrapper');

const tidal = new Tidal();

const getTrackInfos = async (artistData, artistId) => {
  signale.pending('Fetching artist tracks. This might take a while.');
  let tracks = await Promise.all(
    artistData.results.data.map(async (album) => {
      if (album.ART_ID === artistId) {
        return await getAlbumTracks(album.ALB_ID);
      }
    })
  );

  return [].concat(...tracks).filter((a) => a);
};

const tidalTrack2Deezer = async (id) => {
  const { isrc } = await tidal.getTrack(id);
  const { data } = await axios.get('https://api.deezer.com/track/isrc:' + isrc);
  const trackInfo = await deezerApi.getTrackInfo(data.id);
  return trackInfo.data.results;
};

const tidalAlbum2Deezer = async (info) => {
  const { upc } = await tidal.getAlbum(info.id);
  const { data } = await axios.get('https://api.deezer.com/album/upc:' + upc);

  let albumInfo = await deezerApi.getAlbumTrackInfo(data.id);
  info.title = albumInfo.data.results.ALB_TITLE;
  info.id = albumInfo.data.results.ALB_ID;
  info.type = 'album';
  info.data = albumInfo.data.results;

  info.tracks = await getAlbumTracks(info.id);
  info.album = info.data;
  return info;
};

const tidalArtist2Deezer = async (info) => {
  const artistInfo = await tidal.getArtistTopTracks(info.id, 1000);

  signale.pending('Fetching tidal artist tracks. This might take a bit longer.');
  const tracks = await Promise.all(
    artistInfo.map(async (track) => {
      try {
        return await tidalTrack2Deezer(track.id);
      } catch (e) {
        return {};
      }
    })
  );

  info.title = artistInfo.title;
  info.data = artistInfo;
  info.tracks = tracks.filter((item) => item.SNG_ID);
  info.type = 'artist';

  return info;
};

const tidalPlaylist2Deezer = async (info) => {
  signale.pending('Fetching tidal playlist. This might take a while.');
  const playlistInfo = await tidal.getPlaylist(info.id);
  const playlistTracks = await tidal.getPlaylistTracks(playlistInfo.uuid);

  const tracks = await Promise.all(
    playlistTracks.map(async (track) => {
      try {
        return await tidalTrack2Deezer(track.id);
      } catch (e) {
        return {};
      }
    })
  );

  info.title = playlistInfo.title;
  info.data = playlistInfo;
  info.tracks = tracks.filter((item) => item.SNG_ID);
  info.type = 'playlist';

  return info;
};

const getDeezerUrlParts = (url) => {
  if (url.startsWith('spotify:')) {
    const spotify = url.split(':');
    url = 'https://open.spotify.com/' + spotify[1] + '/' + spotify[2];
  }

  const isUrl = urlRegex({ exact: true }).test(url);
  if (isUrl) {
    const site = url.match(/deezer.com|tidal.com|spotify.com/);
    if (!site) {
      throw 'Unknown URL: ' + url;
    }
    const urlParts = url.split(/\/(\w+)\/(\d+)/);

    switch (site[0]) {
      case 'deezer.com':
        return {
          type: urlParts[1],
          id: urlParts[2],
        };
      case 'tidal.com':
        const playlistId = url.match(/[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}/);
        return {
          type: 'tidal-' + urlParts[1],
          id: playlistId ? playlistId[0] : urlParts[2],
        };
      case 'spotify.com':
        const { id, type } = spotifyURI.parse(url);
        return {
          type: 'spotify-' + type,
          id,
        };
    }
  } else {
    return {
      type: 'unknown',
      id: url,
    };
  }
};

const downloadTypes = async (url) => {
  try {
    let info = getDeezerUrlParts(url);
    switch (info.type) {
      case 'track':
        let trackInfo = await deezerApi.getTrackInfo(info.id);
        info.title = trackInfo.data.results.SNG_TITLE;
        info.data = trackInfo.data.results;
        info.tracks = [trackInfo.data.results];
        break;
      case 'album':
      case 'audiobook':
        let albumInfo = await deezerApi.getAlbumTrackInfo(info.id);
        info.title = albumInfo.data.results.ALB_TITLE;
        info.data = albumInfo.data.results;
        info.album = albumInfo.data.results;

        info.tracks = await getAlbumTracks(info.id);
        break;
      case 'playlist':
        let playlistInfo = await deezerApi.getPlaylistInfo(info.id);
        info.title = playlistInfo.data.results.TITLE;
        info.data = playlistInfo.data.results;

        let playlist = await deezerApi.getPlaylistTracks(info.id);
        info.tracks = playlist.data.results.data;
        break;
      case 'artist':
        let artistInfo = await deezerApi.getArtistInfo(info.id);
        info.title = artistInfo.data.results.ART_NAME;
        info.data = artistInfo.data.results;

        let discography = await deezerApi.getDiscography(info.id);
        info.tracks = await getTrackInfos(discography.data, info.id);
        break;
      case 'tidal-track':
        info.data = await tidalTrack2Deezer(info.id);
        info.id = info.data.SNG_ID;
        info.type = 'track';
        info.title = info.data.SNG_TITLE;
        info.tracks = [info.data];
        break;
      case 'tidal-album':
        info = await tidalAlbum2Deezer(info);
        break;
      case 'tidal-playlist':
        info = await tidalPlaylist2Deezer(info);
        break;
      case 'tidal-artist':
        info = await tidalArtist2Deezer(info);
        break;
      case 'spotify-track':
        info.type = 'track';
        info.data = await spotify2Deezer(info);
        info.id = info.data.SNG_ID;
        info.title = info.data.SNG_TITLE;
        info.tracks = [info.data];
        break;
      case 'spotify-album':
        info.type = 'album';
        info = await spotify2Deezer(info);
        break;
      case 'spotify-playlist':
        info.type = 'playlist';
        info = await spotify2Deezer(info);
        break;
      case 'spotify-artist':
        info.type = 'artist';
        info = await spotify2Deezer(info);
        break;
    }

    // Display download count for album/playlist/artist
    if (info.tracks && info.tracks.length > 1) {
      signale.info(`Found ${info.tracks.length} tracks. Procedding with download. Be patient.`);
    }
    return info;
  } catch (err) {
    throw err;
  }
};

module.exports = downloadTypes;
